package workers;

import java.beans.PropertyChangeListener;
import java.io.BufferedWriter;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.util.logging.Logger;

import protocol.TransferenciaClienteServidor;
import protocol.TransferenciaServidorCliente;
import application.Server;

public class ServerWorker extends TimedWorker implements Runnable {
	
	private File fileRoot;
	private Socket clientSocket;
	private TransferenciaServidorCliente transferencia;
	
	public ServerWorker( Socket socket, File root , PropertyChangeListener changeListener){
		super( "Atender conexion del cliente" , changeListener );
		fileRoot = root;
		clientSocket = socket;
		startWork();
		transferencia = null;
		setCurrentAction("waiting for turn in poool");
	}

	public void cancelTask(){
		if( transferencia != null ){
			transferencia.setCancelTransfer();
		}
		setCanceled(true);
	}

	@Override
	//takes a fresh connection and does what it must do
	public void run() {
		if(!isCanceled()){
			setCurrentAction("running");
			Logger logger = Logger.getLogger( Server.loggerName );
			try{


				//Descifrar la solicitud del cliente

				BufferedWriter wr = null;
				//			BufferedReader rd = null;
				String result = "";
				String mensaje;	
				String patronBusqueda = "";

				//			rd = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
				//			mensaje = rd.readLine();
				//			rd.close();

				//using this DEPRECATED code instead of the buffered reader
				// the reason being: raw binary data is read from the same input stream 
				// later on.. and apparently the buffering changes the socket's input stream position...
				// yielding a corrupt file size when read as a LONG
				// PROBLEM ARISING FROM THIS USE IS are that bytes are not converted correctly to characters,
				// so tildes and funny non ASCII characters will give bad results :-(
				setCurrentAction("waiting for client command");
				DataInputStream dis = new DataInputStream(clientSocket.getInputStream());
				mensaje = dis.readLine();			
				if (mensaje.startsWith("Buscar"))
				{
					String tipoBusqueda = "";
					patronBusqueda = mensaje.replaceFirst("Buscar","");
					if( patronBusqueda.startsWith(Busquedas.BUSCAR_POR_ANO) ){
						patronBusqueda = patronBusqueda.replaceFirst(Busquedas.BUSCAR_POR_ANO, "");
						tipoBusqueda = Busquedas.BUSCAR_POR_ANO;
					}
					else if( patronBusqueda.startsWith(Busquedas.BUSCAR_POR_FORMATO_ARCHIVO) )
					{
						patronBusqueda = patronBusqueda.replaceFirst(Busquedas.BUSCAR_POR_FORMATO_ARCHIVO, "");
						tipoBusqueda = Busquedas.BUSCAR_POR_FORMATO_ARCHIVO;
					}
					else if( patronBusqueda.startsWith(Busquedas.BUSCAR_POR_NOMBRE_ALBUM) )
					{
						patronBusqueda = patronBusqueda.replaceFirst(Busquedas.BUSCAR_POR_NOMBRE_ALBUM, "");
						tipoBusqueda = Busquedas.BUSCAR_POR_NOMBRE_ALBUM;

					}
					else if( patronBusqueda.startsWith(Busquedas.BUSCAR_POR_NOMBRE_ARCHIVO) )
					{
						patronBusqueda = patronBusqueda.replaceAll(Busquedas.BUSCAR_POR_NOMBRE_ARCHIVO, "");
						tipoBusqueda = Busquedas.BUSCAR_POR_NOMBRE_ARCHIVO;
					}
					else if( patronBusqueda.startsWith(Busquedas.BUSCAR_POR_NOMBRE_ARTISTA) )
					{					
						patronBusqueda = patronBusqueda.replaceAll(Busquedas.BUSCAR_POR_NOMBRE_ARTISTA, "");
						tipoBusqueda = Busquedas.BUSCAR_POR_NOMBRE_ARTISTA;
					}
					else if( patronBusqueda.startsWith(Busquedas.BUSCAR_POR_NOMBRE_CANCION) )
					{
						patronBusqueda = patronBusqueda.replaceFirst(Busquedas.BUSCAR_POR_NOMBRE_CANCION, "");
						tipoBusqueda = Busquedas.BUSCAR_POR_NOMBRE_CANCION;
					}
					else if( patronBusqueda.startsWith(Busquedas.BUSCAR_POR_TAMANO) )
					{
						patronBusqueda = patronBusqueda.replaceFirst(Busquedas.BUSCAR_POR_TAMANO, "");
						tipoBusqueda = Busquedas.BUSCAR_POR_TAMANO;
					}

					taskDescription += ": Buscar " + tipoBusqueda + " "+ patronBusqueda;

					if( !tipoBusqueda.equals("")){
						Busquedas busq = new Busquedas();
						result = busq.buscarArchivos(tipoBusqueda, fileRoot, patronBusqueda);
					}

					//enviar la lista de archivos
					wr = new BufferedWriter(new OutputStreamWriter(clientSocket.getOutputStream()));
					wr.write(result + "\n");
					wr.flush();
				}				
				else if (mensaje.startsWith("Get"))
				{		
					taskDescription += ": Get";

					logger.fine("Servidor recibe mensaje: " + mensaje );
					mensaje = mensaje.replaceFirst("Get", "");
					DataOutputStream flujo = new DataOutputStream(clientSocket.getOutputStream());
					DataInputStream flujoEntrada = new DataInputStream( clientSocket.getInputStream());
					//enviar un archivo
					File archivo = new File( fileRoot.getPath() + File.separatorChar + mensaje );
					if(archivo.exists()){
						logger.fine("Archivo si existe. Enviando. ");
						transferencia = new TransferenciaServidorCliente( flujo, flujoEntrada , archivo , this );
						transferencia.run();
					}
					else{
						logger.fine("Archivo no existe " + archivo.getPath());
					}
				}
				else if (mensaje.startsWith("Up"))
				{

					taskDescription += ": Up";

					mensaje = mensaje.replaceFirst("Up", "");

					File storePath;
					int count = 0;
					do{
						if( count == 0 ) storePath = new File( fileRoot.getPath() + File.separatorChar + mensaje );
						else storePath = new File( fileRoot.getPath() + File.separatorChar + count + mensaje );
						count ++;
					}while ( !storePath.createNewFile() );


					logger.fine("Servidor preparandose para recibir un archivo y guardarlo en " + storePath.getPath());

					TransferenciaClienteServidor tcs = new TransferenciaClienteServidor(clientSocket, storePath , this);										
					tcs.run();
				}

				clientSocket.shutdownInput();
				clientSocket.shutdownOutput();
				clientSocket.close();
				setCurrentAction("socket shut down and closed");
			}
			catch (Exception e) {
				logger.severe( e.getMessage() );
				e.printStackTrace();
				setCurrentAction("failed with " + e.getClass().getCanonicalName());
			}
			//when finished doing what needs to be done, stop the timer.
			stopWork();
		}
	}
}
